﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging;
using System.IO;
using mds.Common;


namespace mds.Queue.MSMQClient
{
    public class MSMQClientProvider
    {
        private static MSMQClientProvider _intance = new MSMQClientProvider();

        public static MSMQClientProvider Intance
        {
            get { return MSMQClientProvider._intance; }

        }
        /// <summary>
        /// 默认配置下生成消息数据
        /// 发送失败会硬盘本地储存
        /// </summary>
        /// <typeparam name="T">要传递的数据类型</typeparam>
        /// <param name="messageData">要传递的数据</param>
        /// <param name="errMsg">函数内异常返回信息，默认为string.Empty</param>
        /// <param name="logType">消息队列日志类型</param>
        /// <returns></returns>
        public bool CreateMessage<T>(T messageData, out string errMsg, MsmqLogType logType)
        {
            return CreateMessage<T>(MSMQClientConfig.Intance.DefaultMSMQPath, messageData, out errMsg, logType, MSMQClientConfig.Intance.ExceptionDataPath);
        }
        /// <summary>
        /// 生成消息数据
        /// 发送失败会硬盘本地储存
        /// </summary>
        /// <typeparam name="T">要传递的数据类型</typeparam>
        /// <param name="msmqPath">消息队列路径</param>
        /// <param name="messageData">要传递的数据</param>
        /// <param name="errMsg">函数内异常返回信息，默认为string.Empty</param>
        /// <param name="logType">消息队列日志类型</param>
        /// <param name="exceptionDataPath">发生异常后消息队列数据序列化存储的硬盘位置</param>
        /// <returns>成功返回true失败返回false</returns>
        public bool CreateMessage<T>(string msmqPath, T messageData, out string errMsg, MsmqLogType logType, string exceptionDataPath)
        {
            byte[] data = SerializeHelper.ConvertToBytes(messageData);
            errMsg = string.Empty;
            MsmqLogEntity msg = new MsmqLogEntity()
            {
                LogType = MsmqLogType.Opt,
                MsgData = data
            };
            MessageQueue msmq = new MessageQueue(msmqPath);
            msmq.Formatter = new XmlMessageFormatter();
            try
            {
                msmq.DefaultPropertiesToSend.Recoverable = true;
                msmq.Send(msg);
            }
            catch (Exception ex)
            {
                errMsg = ex.Message;
                ErrorDataSaveToFile(exceptionDataPath, logType, new object[] { messageData });
                return false;
            }
            return true;
        }
        /// <summary>
        /// 把日志对象序列化成XML保存到硬盘
        /// </summary>
        /// <param name="basePath">基础路径</param>
        /// <param name="logType">日志类型</param>
        /// <param name="obj">数据对象</param>
        private void ErrorDataSaveToFile(string basePath, MsmqLogType logType, object[] objArray)
        {
            if (objArray != null && objArray.Length > 0)
            {
                string fileFullName, xml, dir;
                foreach (var obj in objArray)
                {
                    fileFullName = GetFileFullName(basePath, logType);
                    try
                    {
                        xml = SerializeHelper.ToXml(obj);
                        dir = Path.GetDirectoryName(fileFullName);
                        if (!Directory.Exists(dir))
                        {
                            Directory.CreateDirectory(dir);
                        }
                        using (StreamWriter writer = File.CreateText(fileFullName))
                        {
                            writer.Write(xml);
                            writer.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                    }
                }
            }
        }
        private string GetFileFullName(string basePath, MsmqLogType logType)
        {
            string fileName = Guid.NewGuid().ToString() + ".xml";
            string fileFullName = Path.Combine(basePath, logType.ToString() + "\\" + DateTime.Now.ToString("yyyyMMdd") + "\\" + fileName);
            return fileFullName;
        }
    }
}
